/*********************************************************************
 * ThreadGate.java created on Feb 26, 2010
 *
 * This file is part of Sure Tech Support Portal System. 
 * Copyright @ 2010 Sure Tech (HK) Limited. All rights reserved.
 * Sure Tech PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *********************************************************************/
package demo.concurrent.primefinder;

/**
 * @Author: Mac Wang
 * @Date: Feb 26, 2010 11:01:39 AM 
 * @Email: mac@suretech.com.hk
 */

public class ThreadGate {
	//This field tracks the generation index of waiting threads. 
	//It helps ensure fairness, because the threads that are let through are the last set of threads to arrive -- counting from the last time the gate was opened. 
	//Its value is incremented each time the open() method is invoked, thus forcing subsequent thread arrivals into a new, younger generation. 
	private int waitPosition;
	
	//Tracks the size of the current generation of threads waiting for the gate to open. 
	//Its value should be reset each time the open() or close() method is invoked. 
	private int generationSize;
	
	//An integer counter indicating the number of attempts that have been made to open the gate since the last time it was closed. 
	//In practice, it actually tracks the number of results that have been added to the results buffer since the last time the gate was closed. 
	//This should be apparent on examining the result handle implementation com.javaworld.primefinder.ConcurrentPrimeNumberSource, 
	//which shows that the open() method is invoked each time a new prime number is added to the results buffer. 
	//The value of this field is not only altered by calling open() but is also reset to zero with each call to close(). 
	private int openAttempts;
	
	//Reader threads should not wait needlessly if there is no prospect of any further results being made available. 
	//A key indicator of the prospect of further results is whether or not there are still any active search threads. 
	//As such, it is important that the gate keep track of the number of active search threads. 
	//If this number is equal to zero, then the await() method will not block, thus allowing reader threads free passage through the gate. 
	private int activeSearchThreads;
	
	//A binary value that indicates whether the gate is open or closed. 
	private boolean open;
	
	public ThreadGate(int searchThreadsCount)
	{
		activeSearchThreads = searchThreadsCount;
		waitPosition = 0;
		generationSize = 0;
		openAttempts = 0;
		open = true;
	}
	
	public synchronized void await() throws InterruptedException
	{
		int generationIndex = waitPosition;
		generationSize++;
		while (!open && generationIndex ==waitPosition
			&& activeSearchThreads!=0)
			wait();
	}

	public synchronized void close() throws InterruptedException
	{
		open = false;
		openAttempts =0;
		generationSize = 0;
	}
	
	public synchronized void open()
	{
		openAttempts++;
		
		if (generationSize<=openAttempts)
		{
			++waitPosition; //reset the counter		
			open=true;
			generationSize = 0;
			notifyAll();			
		}
	}
	
	synchronized void threadCompleted()
	{
		--activeSearchThreads;
		notifyAll();
	}		
	
	synchronized boolean isActive() {return activeSearchThreads!=0;}
	
	synchronized boolean isClosed(){return !open;}
}
